package com.gitee.jktantan.datasource.monitor.analyze.p6spy;


import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Snapshot;
import com.gitee.jktantan.datasource.monitor.analyze.entity.HistogramEntity;
import com.gitee.jktantan.datasource.monitor.config.DataSourceMonitorRegister;
import com.gitee.jktantan.datasource.monitor.toolkit.MD5Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * p6spy的数据收集器
 */
@Component
public class QueryCollector {
    private static final String EXECUTION_TIME = ".sql.ExecutionTime";
    private ConcurrentMap<String, List<StatisticsEntry>> queryList = new ConcurrentHashMap<>();
    private Set dataSourceSet = new HashSet<>();
    private ExecutorService executor = Executors.newFixedThreadPool(5);
    private FixSizeLinkedList<String> statementList = new FixSizeLinkedList<>(500);
    @Autowired(required = false)
    private MetricRegistry metricRegistry;
    @Autowired
    private DataSourceMonitorRegister dataSourceMonitorProperties;

    /**
     * 获取状态
     *
     * @return 返回SQL状态
     */
    public Object getStatistics(String id) {
        if (id != null) {
            return getStatistics(queryList.get(id));
        } else {
            for (Map.Entry<String, List<StatisticsEntry>> entry : queryList.entrySet()) {
                List<StatisticsEntry> statisticsEntries = entry.getValue();
                getStatistics(statisticsEntries);
            }
            return queryList;
        }

    }

    /**
     * 获取P6PSY所有数据库
     *
     * @return
     */
    public Set getDataSourceSet() {
        return this.dataSourceSet;
    }
    /**
     * 获取并生成状态
     *
     * @param statisticsEntries 要生成的状态列表
     * @return 生成好的状态
     */
    private Object getStatistics(List<StatisticsEntry> statisticsEntries) {
        List<StatisticsEntry> result = new ArrayList<>();
        for (StatisticsEntry statisticsEntity : statisticsEntries) {
            HistogramEntity executeTime = new HistogramEntity();
            Histogram histogram = metricRegistry.getHistograms().get(statisticsEntity.getId() + EXECUTION_TIME);
            if (histogram != null) {
                executeTime.setCount(histogram.getCount());

                Snapshot snapshot = histogram.getSnapshot();

                executeTime.setMin(snapshot.getMin());
                executeTime.setMax(snapshot.getMax());
                executeTime.setMean(snapshot.getMean());
                executeTime.setStdDev(snapshot.getStdDev());
                executeTime.setP50(snapshot.getMedian());
                executeTime.setP75(snapshot.get75thPercentile());
                executeTime.setP95(snapshot.get95thPercentile());
                executeTime.setP98(snapshot.get98thPercentile());
                executeTime.setP99(snapshot.get99thPercentile());
                executeTime.setP999(snapshot.get999thPercentile());

            }
            statisticsEntity.setStatus(executeTime);
            result.add(statisticsEntity);

        }
        return result;
    }

    public void collectQueryStatement(final String statement) {
        this.statementList.add(statement);
    }

    public List<String> getQueryStatement() {
        return this.statementList;
    }
    /**
     * 收集SQL查询数据
     *
     * @param queryEntry 查询数据
     */
    public void collectQuery(final QueryEntry queryEntry) {
        //判断metric是否为空，且是否统计
        if (metricRegistry != null && dataSourceMonitorProperties.isEnable()) {
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    //获取ID
                    String id = MD5Utils.MD5Encode(queryEntry.getUrl() + queryEntry.getPreparedSQL() + queryEntry.getCategory(), null);
                    //注册
                    metricRegistry.histogram(id + EXECUTION_TIME).update(queryEntry.getElapsedTime());
                    updateQueryList(queryEntry, id);
                    updateDataSourceList(queryEntry.getUrl(), id);
                }
            });

        }
    }

    /**
     * 更新数据库
     *
     * @param url 连接URL
     * @param id  数据库ID
     */
    private void updateDataSourceList(final String url, final String id) {
        DataSourceEntry dataSourceEntry = new DataSourceEntry();
        dataSourceEntry.setId(id);
        dataSourceEntry.setUrl(url);
        dataSourceSet.add(dataSourceEntry);
    }

    /**
     * 更新查询列表
     *
     * @param queryEntry
     * @param id
     */
    private void updateQueryList(final QueryEntry queryEntry, final String id) {
        List<StatisticsEntry> statisticsEntries = queryList.get(id);
        StatisticsEntry statisticsEntry;
        if (statisticsEntries == null) {
            statisticsEntries = new ArrayList<>();
            queryList.put(id, statisticsEntries);
        }
        for (int i = 0; i < statisticsEntries.size(); i++) {
            statisticsEntry = statisticsEntries.get(i);
            if (statisticsEntry.getId().equals(id)) {
                return;
            }
        }
        statisticsEntry = new StatisticsEntry();
        statisticsEntry.setId(id);
        statisticsEntry.setCategory(queryEntry.getCategory());
        statisticsEntry.setSql(queryEntry.getSqlStatement());
        statisticsEntry.setUrl(queryEntry.getUrl());
        statisticsEntries.add(statisticsEntry);
    }
}
